Parsing JSON Responses Using Kotlin Serialization or Gson
Course: Android App Development
Topic: Parsing JSON Responses Using Kotlin Serialization or Gson
Course Link: Android App Development Course
Demo Link: Register for a Free Course Demo
Website: JustAcademy
1. Introduction to JSON Parsing in Android
Modern Android applications frequently communicate with web services to retrieve information such as user profiles, product details, weather updates, news articles, orders, and payment statuses. These services commonly send data in JSON (JavaScript Object Notation) format.
JSON is a lightweight, text-based data format that represents information using objects, arrays, strings, numbers, Boolean values, and null values. Android applications often receive JSON responses from REST APIs and convert them into Kotlin objects so that the data can be processed and displayed in the user interface.
JSON parsing is the process of reading JSON data and extracting or converting it into a usable structure. When JSON is converted into Kotlin data classes, the process is commonly called deserialization.
Two commonly used libraries for handling JSON in Kotlin-based Android applications are:
- Kotlin Serialization: A Kotlin-focused serialization library that uses annotations and generated serializers.
- Gson: A Java library from Google that converts Java or Kotlin objects to JSON and parses JSON into objects.
Both libraries can simplify API response handling, but their configuration, supported features, and approaches differ. Kotlin Serialization is especially convenient in Kotlin-first projects, while Gson remains common in existing Java and Android applications.
2. Learning Objectives
- Understand JSON objects, arrays, and primitive values.
- Learn how API responses are converted into Kotlin data classes.
- Configure Kotlin Serialization and Gson in an Android project.
- Parse simple, nested, nullable, and collection-based JSON responses.
- Map JSON field names to Kotlin property names.
- Handle malformed JSON and unexpected API response structures.
- Integrate JSON parsing with Retrofit, coroutines, repositories, and ViewModels.
- Apply security and performance best practices when processing API data.
3. Understanding JSON Structure
Before implementing a parser, it is important to understand the JSON structure returned by an API.
3.1 JSON Object
A JSON object is a collection of key-value pairs enclosed in curly braces. Each key is a string, and its value may be a string, number, Boolean, object, array, or null.
{
"id": 101,
"name": "Aarav",
"email": "[email protected]",
"active": true
}
3.2 JSON Array
A JSON array contains an ordered collection of values enclosed in square brackets. APIs commonly use arrays to return multiple records.
[
{
"id": 101,
"name": "Aarav"
},
{
"id": 102,
"name": "Meera"
}
]
3.3 Nested JSON
Nested JSON contains an object or array inside another object. Kotlin models should represent the same structure when using typed deserialization.
{
"id": 101,
"name": "Aarav",
"address": {
"city": "Mumbai",
"country": "India"
}
}
3.4 JSON Data Types
| JSON Type |
Example |
Typical Kotlin Type |
| String |
"Aarav" |
String |
| Integer |
25 |
Int or Long |
| Decimal |
99.5 |
Double or Float |
| Boolean |
true |
Boolean |
| Array |
[1, 2, 3] |
List<Int> |
| Object |
{"city":"Mumbai"} |
A data class |
| Null |
null |
A nullable Kotlin type, such as String? |
4. What Is Deserialization?
Deserialization converts structured data, such as a JSON string, into an application object. For example, a response containing a user's name and email can be converted into a Kotlin data class.
The general process is:
- The Android application sends a request to an API.
- The server processes the request and returns a response.
- The networking layer receives the response body.
- A JSON converter reads the response structure.
- The converter maps JSON fields to Kotlin properties.
- The application uses the resulting object in its repository, ViewModel, and UI.
API Response
|
v
JSON Response Body
|
v
Kotlin Serialization or Gson
|
v
Kotlin Data Class / Model
|
v
Repository and ViewModel
|
v
Android UI
5. Parsing JSON Using Kotlin Serialization
Kotlin Serialization is a serialization framework designed for Kotlin. Its JSON library provides functions to convert JSON strings into objects and Kotlin objects into JSON strings. Classes intended for typed parsing are generally marked with the @Serializable annotation.
Unlike Gson's usual reflective approach, Kotlin Serialization normally relies on serializers generated by its compiler plugin. This gives the library strong integration with Kotlin types and compile-time serialization support.
5.1 Add Kotlin Serialization Dependencies
For a Gradle Kotlin DSL project, apply the serialization plugin using a version compatible with the Kotlin version configured in your project.
Module or project Gradle configuration example:
// build.gradle.kts
plugins {
// Keep the version aligned with your project's Kotlin version.
id("org.jetbrains.kotlin.plugin.serialization") version "YOUR_KOTLIN_VERSION"
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:YOUR_SERIALIZATION_VERSION")
}
Replace the placeholders with compatible versions. In Android projects using a version catalog, declare the plugin and library in the catalog and apply them through the project's existing Gradle conventions. Do not add a second conflicting Kotlin plugin version.
5.2 Create a Serializable Data Class
Suppose an API returns the following response:
{
"id": 101,
"name": "Aarav",
"email": "[email protected]",
"active": true
}
Create a model that represents the response:
import kotlinx.serialization.Serializable
@Serializable
data class User(
val id: Int,
val name: String,
val email: String,
val active: Boolean
)
The @Serializable annotation enables Kotlin Serialization to generate a serializer for the class when the plugin is correctly configured. Property types should match the expected JSON value types.
5.3 Parse a JSON String
Use Json.decodeFromString() to convert the JSON string into a typed Kotlin object.
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
fun parseUser(jsonString: String): User {
return Json.decodeFromString<User>(jsonString)
}
Example usage:
fun main() {
val response = """
{
"id": 101,
"name": "Aarav",
"email": "[email protected]",
"active": true
}
""".trimIndent()
val user = parseUser(response)
println(user.name)
println(user.email)
}
Output:
Aarav
[email protected]
5.4 Configure the JSON Parser
APIs sometimes return additional fields that are not represented in the application's data class. By default, unknown keys can cause deserialization to fail. You can configure the parser to ignore them when appropriate.
import kotlinx.serialization.json.Json
val appJson = Json {
ignoreUnknownKeys = true
}
Use the configured instance for parsing:
val user = appJson.decodeFromString<User>(responseJson)
Other useful configuration options include:
| Option |
Purpose |
Important Consideration |
ignoreUnknownKeys |
Ignores JSON fields not declared in the model. |
Useful when the API adds fields that the app does not need. |
isLenient |
Allows certain relaxed JSON syntax. |
Do not enable it without a clear requirement. |
coerceInputValues |
Can replace certain invalid values for supported properties with configured defaults. |
Understand which values are coerced and which still fail. |
encodeDefaults |
Controls whether default property values are included during encoding. |
Primarily affects serialization to JSON, not ordinary response parsing. |
explicitNulls |
Controls null handling during JSON encoding and decoding behavior. |
Review the API contract before changing it. |
5.5 Handle Missing and Nullable Fields
Consider a response in which the email may be absent or null. Model this possibility explicitly.
@Serializable
data class UserProfile(
val id: Int,
val name: String,
val email: String? = null
)
Here, email is nullable and has a default value. The default makes the property optional during deserialization when the field is missing. A nullable property without a default does not automatically make the JSON field optional.
For example, a response containing only id and name can be parsed into this model, and the email will be null.
5.6 Map Different JSON Field Names
API naming conventions may differ from Kotlin naming conventions. Use @SerialName to map a JSON key to a Kotlin property.
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class Product(
val id: Int,
@SerialName("product_name")
val productName: String,
@SerialName("unit_price")
val unitPrice: Double
)
Example JSON:
{
"id": 5,
"product_name": "Keyboard",
"unit_price": 1499.0
}
The application can access product.productName and product.unitPrice while preserving the field names expected by the API.
5.7 Parse Nested JSON
For a nested response, define separate serializable classes for the nested objects.
@Serializable
data class Address(
val city: String,
val country: String
)
@Serializable
data class Customer(
val id: Int,
val name: String,
val address: Address
)
Example parsing:
val jsonString = """
{
"id": 1,
"name": "Meera",
"address": {
"city": "Pune",
"country": "India"
}
}
""".trimIndent()
val customer = appJson.decodeFromString<Customer>(jsonString)
println(customer.address.city)
Output: Pune
5.8 Parse a JSON Array
If an API returns a list of users, deserialize it as a list of the model type.
val jsonArray = """
[
{"id": 1, "name": "Aarav", "email": "[email protected]", "active": true},
{"id": 2, "name": "Meera", "email": "[email protected]", "active": false}
]
""".trimIndent()
val users = appJson.decodeFromString<List<User>>(jsonArray)
users.forEach { user ->
println("${user.id}: ${user.name}")
}
When an API returns a wrapper object instead of a raw array, create a wrapper model matching that structure rather than trying to parse the entire response as a list.
6. Parsing JSON Using Gson
Gson is a JSON library that converts JSON strings into Java or Kotlin objects and converts objects into JSON. It is commonly used in Android projects, including applications that already rely on Gson with Retrofit.
6.1 Add the Gson Dependency
Add Gson to the application's module-level Gradle file. Use the version approved for your project.
// build.gradle.kts
dependencies {
implementation("com.google.code.gson:gson:YOUR_GSON_VERSION")
}
Replace the placeholder with a valid dependency version. If Retrofit is already configured with a Gson converter, you may not need to add Gson separately unless the dependency is not already included.
6.2 Create a Kotlin Data Class
For the same user response, create a matching data class.
data class User(
val id: Int,
val name: String,
val email: String,
val active: Boolean
)
Gson can generally map JSON fields to properties by name without requiring a serialization annotation on the class. For reliable Android behavior, ensure that the model's fields and types match the response and test the model with the project's actual minification and build configuration.
6.3 Parse JSON Using Gson
Create a Gson instance and call fromJson().
import com.google.gson.Gson
fun parseUserWithGson(jsonString: String): User {
return Gson().fromJson(jsonString, User::class.java)
}
Example:
fun main() {
val response = """
{
"id": 101,
"name": "Aarav",
"email": "[email protected]",
"active": true
}
""".trimIndent()
val user = parseUserWithGson(response)
println(user.name)
println(user.active)
}
Output:
Aarav
true
6.4 Map JSON Field Names with SerializedName
Gson provides the @SerializedName annotation for JSON keys that differ from Kotlin property names.
import com.google.gson.annotations.SerializedName
data class ProductGson(
val id: Int,
@SerializedName("product_name")
val productName: String,
@SerializedName("unit_price")
val unitPrice: Double
)
This model maps product_name to productName and unit_price to unitPrice.
6.5 Parse a JSON Array with Gson
Gson can parse arrays into a typed list. For generic types such as List<User>, use a TypeToken to preserve the generic type information.
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
val gson = Gson()
val userListType = object : TypeToken<List<User>>() {}.type
val users: List<User> = gson.fromJson(jsonArray, userListType)
users.forEach { user ->
println(user.name)
}
For nested JSON, create nested data classes just as you would with Kotlin Serialization. Gson maps nested objects when the response structure and model types match.
7. Kotlin Serialization vs. Gson
Both libraries support common JSON parsing tasks, but they use different mechanisms and have different trade-offs.
| Feature |
Kotlin Serialization |
Gson |
| Primary ecosystem |
Kotlin-first and multiplatform |
Java and Android ecosystem |
| Typical model setup |
Uses @Serializable |
Usually maps fields by name; annotations are available for custom names |
| Parsing method |
Json.decodeFromString<T>() |
Gson.fromJson() |
| Serializer mechanism |
Compiler-generated serializers for annotated models |
Typically reflection-based mapping |
| Unknown fields |
Can be ignored with ignoreUnknownKeys = true |
Unknown fields are generally ignored by default |
| Nullable fields |
Represent nullability in the Kotlin model and configure defaults deliberately |
Nullable references are supported; missing fields and constructor/default behavior require care |
| Generic lists |
Supports typed collections through serializers |
Often requires TypeToken for generic types |
| Retrofit integration |
Available through a Kotlin Serialization converter |
Available through a Gson converter |
| Best fit |
Kotlin-first projects that benefit from generated, type-aware serializers |
Existing applications or projects already standardized on Gson |
Recommendation: For a new Kotlin-first Android application, consider Kotlin Serialization when it fits your build setup and networking stack. Choose Gson when maintaining an existing Gson-based codebase or when its behavior is required by your project. Avoid adding multiple JSON converters without a clear reason.
8. Integrating JSON Parsing with Retrofit
Retrofit is a networking library that turns HTTP API definitions into Kotlin interfaces. A converter can read a successful response body and deserialize it into the return type declared by the API method.
When Retrofit is configured correctly, you usually do not need to manually call decodeFromString() or fromJson() for every response. Retrofit invokes the configured converter.
8.1 Define a Retrofit API Interface
import retrofit2.http.GET
import retrofit2.http.Path
interface UserApi {
@GET("users/{id}")
suspend fun getUser(
@Path("id") userId: Int
): User
}
This example assumes the API returns a user JSON object matching the User model. The base URL must be configured separately and end with a slash when required by Retrofit's URL resolution.
8.2 Configure Retrofit with Kotlin Serialization
Add the Retrofit converter dependency compatible with your Retrofit version, then register its factory.
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.Retrofit
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
val json = Json {
ignoreUnknownKeys = true
}
val contentType = "application/json".toMediaType()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(json.asConverterFactory(contentType))
.build()
val userApi = retrofit.create(UserApi::class.java)
Use the Kotlin Serialization Retrofit converter dependency that matches your Retrofit and Kotlin Serialization setup. The URL above is an example placeholder, not a real service endpoint.
8.3 Configure Retrofit with Gson
For a Gson-based application, register the Gson converter instead.
import com.google.gson.Gson
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
val gson = Gson()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
val userApi = retrofit.create(UserApi::class.java)
In either configuration, the API method's declared return type tells the converter which model to create from the response body.
9. Use a Repository and ViewModel
JSON parsing should not be performed directly inside a button click handler or composable UI function. A repository can manage data access, while a ViewModel exposes loading, success, and error states to the UI.
9.1 Create a Repository
class UserRepository(
private val api: UserApi
) {
suspend fun getUser(userId: Int): User {
return api.getUser(userId)
}
}
9.2 Create UI State
sealed interface UserUiState {
data object Loading : UserUiState
data class Success(val user: User) : UserUiState
data class Error(val message: String) : UserUiState
}
9.3 Load Data in a ViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _uiState =
MutableStateFlow<UserUiState>(UserUiState.Loading)
val uiState: StateFlow<UserUiState> =
_uiState.asStateFlow()
fun loadUser(userId: Int) {
viewModelScope.launch {
_uiState.value = UserUiState.Loading
try {
val user = repository.getUser(userId)
_uiState.value = UserUiState.Success(user)
} catch (e: IOException) {
_uiState.value =
UserUiState.Error("Network connection failed.")
} catch (e: HttpException) {
_uiState.value =
UserUiState.Error("Server returned HTTP ${e.code()}.")
} catch (e: Exception) {
_uiState.value =
UserUiState.Error("Unable to load user data.")
}
}
}
}
This example demonstrates the basic flow. In a production application, use structured logging, safe error classification, dependency injection where appropriate, and appropriate handling for cancellation. Do not expose raw exception details or sensitive server responses to users.
10. Handling API Response Wrappers
Some APIs return a wrapper object containing metadata and the actual data instead of returning a user directly.
{
"success": true,
"message": "User retrieved successfully",
"data": {
"id": 101,
"name": "Aarav",
"email": "[email protected]",
"active": true
}
}
Represent the response structure with a wrapper model.
@Serializable
data class UserResponse(
val success: Boolean,
val message: String,
val data: User
)
For Gson, create the same structure without @Serializable, provided the model fields and annotations are appropriate. If the server returns an error wrapper with a different shape, do not assume it can be parsed as the success model.
11. Working with Optional, Missing, and Null Values
Real-world APIs may omit fields, return explicit nulls, or introduce new fields over time. Models must reflect the API contract rather than assume every property is always present.
| Situation |
Recommended Handling |
| Field always exists and is required |
Use a non-null property with the correct type. |
| Field may be null |
Use a nullable type such as String?. |
| Field may be missing |
Use a suitable default value if absence has a meaningful interpretation. |
| Field may contain an unexpected type |
Validate the API contract and handle conversion failures; do not silently assume correctness. |
| New, unused fields are added |
Configure unknown-field behavior intentionally for the selected parser. |
Be careful with default values. Replacing missing IDs with zero or missing prices with zero may hide a data problem. Choose defaults only when they are valid for the application's business logic.
12. Handling Parsing Errors
Parsing can fail if the response is malformed, the server returns an unexpected type, a required field is missing, or a converter cannot construct the requested model.
12.1 Common Error Types
| Problem |
Possible Cause |
Suggested Action |
| Malformed JSON |
Missing comma, invalid quotation marks, or truncated response |
Inspect the response and fix the server or test data. |
| Missing required field |
Response does not match the model |
Confirm whether the field should be optional or required. |
| Type mismatch |
API returns a string where a number is expected |
Correct the API contract or implement explicit conversion. |
| Unknown key error |
Response contains fields absent from the Kotlin Serialization model |
Use ignoreUnknownKeys only when ignoring extra fields is appropriate. |
| Unexpected HTML response |
Server, proxy, or gateway returns an error page instead of JSON |
Inspect the HTTP status, content type, and server logs. |
| Empty response body |
Endpoint returns no body or a response with no content |
Use a response type that matches the endpoint contract. |
12.2 Safely Parse a Local JSON String
When parsing a standalone string, you can catch expected serialization errors and return a controlled result.
import kotlinx.serialization.SerializationException
fun parseUserSafely(jsonString: String): Result<User> {
return runCatching {
appJson.decodeFromString<User>(jsonString)
}.recoverCatching { error ->
if (error is SerializationException) {
throw IllegalArgumentException(
"The response format is invalid.",
error
)
}
throw error
}
}
For a real application, consider defining a dedicated result type and logging the underlying cause safely. Avoid catching every exception and pretending that parsing succeeded. Do not log access tokens, passwords, or private response fields.
13. Dynamic JSON and Unknown Structures
Not every API response has a stable structure. Some endpoints return arbitrary metadata or values whose exact shape is not known in advance. Kotlin Serialization provides JSON tree types such as JsonObject, JsonArray, and JsonPrimitive for inspecting JSON dynamically.
import kotlinx.serialization.json.*
val jsonElement = appJson.parseToJsonElement(
"""{"status":"ok","count":3}"""
)
val jsonObject = jsonElement.jsonObject
val status = jsonObject["status"]?.jsonPrimitive?.content
val count = jsonObject["count"]?.jsonPrimitive?.int
println(status)
println(count)
Dynamic parsing is useful for flexible metadata, but typed data classes are usually preferable for predictable business entities because they make the expected structure clearer.
14. Parsing JSON in the Android UI
After a response has been converted into a Kotlin object, the UI can display its properties. In Jetpack Compose, collect the ViewModel's state and render the appropriate screen for loading, success, or error.
@Composable
fun UserScreen(viewModel: UserViewModel) {
val state by viewModel.uiState.collectAsState()
when (val current = state) {
UserUiState.Loading -> {
CircularProgressIndicator()
}
is UserUiState.Success -> {
Column {
Text(text = current.user.name)
Text(text = current.user.email)
}
}
is UserUiState.Error -> {
Text(text = current.message)
}
}
}
Required Compose imports include the relevant layout, material, state-collection, and text APIs. The ViewModel must be supplied through your application's chosen dependency-injection or ViewModel creation approach. Keep network calls and JSON parsing outside composable functions.
15. Performance and Security Best Practices
- Use typed models: Create data classes that accurately represent the API response.
- Keep parsing off the main thread when necessary: Large JSON payloads can be expensive to process. Use an appropriate background execution strategy and profile the application.
- Use Retrofit converters consistently: Avoid manually parsing the same response again when the converter already provides a typed object.
- Choose appropriate numeric types: Use
Long for large integer values and an appropriate decimal representation for the business requirement.
- Handle nullable fields deliberately: Reflect optional API fields in your model.
- Do not blindly ignore errors: Log useful diagnostic information without exposing private data.
- Validate important values: Successful parsing does not prove that a response is logically correct.
- Protect sensitive information: Do not store or print credentials and tokens unnecessarily.
- Use HTTPS: Protect network communication in transit and follow Android network security guidance.
- Limit response size: Avoid loading unnecessarily large payloads into memory; use pagination for large collections.
- Test release builds: Verify serialization behavior under code shrinking and obfuscation settings.
- Keep dependencies compatible: Align Kotlin, the serialization plugin, the serialization runtime, Retrofit, and converter versions.
16. Common Mistakes and Troubleshooting
| Mistake |
Why It Happens |
Solution |
Forgetting @Serializable |
The serializer cannot be generated for the model. |
Add the annotation and apply the Kotlin Serialization plugin. |
| Plugin version mismatch |
Gradle or Kotlin compilation fails. |
Align plugin versions with the Kotlin version in the project. |
| Incorrect property names |
JSON keys do not match model properties. |
Use @SerialName or Gson's @SerializedName. |
| Parsing a list as a single object |
The API returns an array instead of an object. |
Use a collection model or a wrapper class matching the response. |
| Assuming a field is always present |
Some API records omit optional values. |
Model optional fields with appropriate nullable types and defaults. |
| Manually parsing every Retrofit response |
The converter is not being used effectively. |
Declare typed return values and register the correct converter. |
| Parsing an HTTP error as success data |
Error responses may have a different JSON structure. |
Handle HTTP status codes and error bodies separately. |
| Using a placeholder base URL |
The sample URL was not replaced. |
Configure the real API base URL and verify the endpoint path. |
17. Practical Exercise
Exercise: Build a User Directory Screen
Create a small Android application that fetches a list of users from a REST API and displays their names and email addresses.
Requirements
- Create a
User data class with an ID, name, email, and active status.
- Choose either Kotlin Serialization or Gson.
- Configure Retrofit with the matching converter.
- Define an API interface that retrieves a list of users.
- Create a repository that requests the list.
- Use a ViewModel to expose loading, success, and error states.
- Display the user list using a Compose
LazyColumn or a RecyclerView.
- Show a loading indicator while the request is running.
- Display a meaningful error message if the request or parsing fails.
- Test the application with missing fields, unexpected extra fields, and an invalid JSON response.
Expected Learning Outcome
After completing the exercise, you should understand how JSON responses are mapped to Kotlin objects, how a converter integrates with Retrofit, and how parsed data moves from a repository to the Android UI.
18. Mini Project: Product Catalog
Extend the exercise into a product catalog that retrieves product information from an API.
Suggested product model:
@Serializable
data class CatalogProduct(
val id: Int,
@SerialName("product_name")
val productName: String,
val price: Double,
val description: String? = null,
val inStock: Boolean = false
)
Make sure the property names match the actual API contract. For example, if the API returns in_stock rather than inStock, annotate the property with @SerialName("in_stock").
Features to implement:
- Fetch products from the API.
- Parse the response using your selected library.
- Display product name, price, stock status, and optional description.
- Add a search field to filter products locally.
- Handle empty results and network failures.
- Add pagination if the API returns a large collection.
- Write unit tests for model parsing and repository behavior.
19. Interview Questions and Answers
Q1. What is JSON parsing?
Answer: JSON parsing is the process of reading JSON data and converting it into a structure that an application can access. In Android, it commonly means converting an API response into Kotlin objects.
Q2. What is deserialization?
Answer: Deserialization converts data from a serialized format, such as JSON, into an object or another usable data structure.
Q3. What is Kotlin Serialization?
Answer: Kotlin Serialization is a Kotlin-oriented serialization framework that supports formats including JSON. It can generate serializers for classes marked with annotations such as @Serializable.
Q4. What is Gson?
Answer: Gson is a Java library that converts Java or Kotlin objects to JSON and parses JSON into objects.
Q5. What is the difference between Kotlin Serialization and Gson?
Answer: Kotlin Serialization uses compiler-generated serializers and is designed around Kotlin's type system. Gson commonly uses reflection-based mapping and is widely used in Java and Android projects.
Q6. Why is @Serializable used?
Answer: It marks a Kotlin class for Kotlin Serialization and allows the configured plugin to generate the serializer required to encode or decode that class.
Q7. What does Json.decodeFromString() do?
Answer: It converts a JSON string into the specified Kotlin type using the serializer available for that type.
Q8. What does Gson's fromJson() do?
Answer: It parses JSON text and converts it into the requested Java or Kotlin class or generic type.
Q9. How do you map a JSON key to a differently named Kotlin property?
Answer: Use @SerialName with Kotlin Serialization or @SerializedName with Gson.
Q10. How do you parse a JSON array?
Answer: With Kotlin Serialization, decode into a type such as List<User>. With Gson, use a collection type and a TypeToken when parsing a generic list.
Q11. What is the purpose of ignoreUnknownKeys?
Answer: It configures Kotlin Serialization to ignore JSON fields that are not declared in the target model, which can help when an API adds unused fields.
Q12. How should optional fields be handled?
Answer: Use nullable properties when a value may be null and defaults when a field may be absent and a default is appropriate. The exact model should follow the API contract.
Q13. How does Retrofit help with JSON parsing?
Answer: Retrofit can use a registered converter to transform successful HTTP response bodies into the model type declared by the API interface.
Q14. Why should parsing errors be handled?
Answer: APIs may return malformed JSON, unexpected field types, missing required values, or error pages. Handling failures prevents application crashes and allows the UI to show a suitable error state.
Q15. Should JSON parsing happen in a composable or Activity click handler?
Answer: Generally, no. Network operations and data conversion should be managed by the data layer, such as a repository, with the ViewModel exposing state to the UI.
20. Quick Revision Checklist
- JSON represents structured data using objects, arrays, and primitive values.
- Deserialization converts JSON into application objects.
- Kotlin Serialization models commonly use
@Serializable.
Json.decodeFromString<T>() parses JSON into a typed object.
- Gson uses
Gson().fromJson() for parsing.
- Use
@SerialName or @SerializedName when field names differ.
- Use nested classes for nested JSON objects.
- Use typed collections for JSON arrays.
- Configure Retrofit with the converter matching the chosen JSON library.
- Handle missing fields, null values, malformed responses, and HTTP errors.
- Keep networking and parsing out of the UI layer.
- Test real response shapes and protect sensitive information.
21. Official Learning Resources
22. Conclusion
Parsing JSON responses is a fundamental skill in Android development because it connects remote API data with application models and user interfaces. Kotlin Serialization and Gson both provide practical ways to convert JSON into Kotlin objects, parse nested structures, map field names, and work with collections.
For maintainable applications, define accurate models, configure the appropriate Retrofit converter, handle nullable and unexpected data deliberately, and expose loading, success, and error states through a clean architecture. Choose the library that best fits the project, keep dependencies compatible, and test the parser against actual API responses.
Explore more learning opportunities through JustAcademy Android App Development, register for a course demo, or visit the JustAcademy website.